﻿namespace Pyramid.Hardware.Cpu
{
    using System.Collections.Generic;
    using System.Linq;
    using Pyramid.Hardware.MicroArchitecture;
    using Pyramid.Hardware.Operations;

    public class Cricket
    {
        public Cricket(int wordSize, int microcodeRomSize, IEnumerable<ILine> inputBus, ILine clockLine)
        {
            var dataBus = new BusLink(wordSize);

            var controlUnit = new SimpleControlUnit(Tryte.TritsPerTryte, microcodeRomSize, clockLine, FixedInputLine.False);

            // Control Value Structure
            // 0: Not Used
            // 1: Not Used
            // 2: Write Selector Line
            // 3: Not Used
            // 4: Read Selector Line
            // 5: Data Request Line
            // 6: Operation Selector Line
            // 7: Data Selector Line
            // 8: Write Flag

            var writeSelectorLine = controlUnit.OutputBus.ElementAt(2);

            var inputSelectorLine = controlUnit.OutputBus.ElementAt(4);

            this.DataRequest = controlUnit.OutputBus.ElementAt(5);

            var controlLine = controlUnit.OutputBus.ElementAt(6);

            var dataSelectorLine = controlUnit.OutputBus.ElementAt(7);

            var writeFlag = controlUnit.OutputBus.ElementAt(8);

            this.RegisterFile = new RegisterFile(dataBus.OutputBus, new[] { inputSelectorLine }, new[] { writeSelectorLine }, writeFlag, clockLine, 3);

            this.Accumulator = this.RegisterFile.OutputBuses.ElementAt(0);

            var alu = new Alu(this.RegisterFile.ReadBus, this.Accumulator, new ILine[] { controlLine }, new IOperationFactory[] { new SubtractOperationFactory(), new AddOperationFactory(), new NotOperationFactory() });

            var dataSelectorBus = new BusMultiplexer(new[] { dataSelectorLine }, alu.OutputBus, inputBus, this.RegisterFile.ReadBus);

            dataBus.InputBus = dataSelectorBus.OutputBus;

            this.ControlStore = controlUnit.ControlStore;
        }

        public RegisterFile RegisterFile
        {
            get;
            private set;
        }

        public IEnumerable<ILine> Accumulator
        {
            get;
            private set;
        }

        public ILine DataRequest
        {
            get;
            private set;
        }

        public AddressableRom ControlStore
        {
            get;
            private set;
        }
    }
}
